﻿using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Linq;

namespace ControlDesktop
{
    class DesktopIcon
    {
        #region API声明
        private const uint LVM_FIRST = 0x1000;
        private const uint LVM_GETITEMCOUNT = LVM_FIRST + 4;
        private const uint LVM_GETITEMW = LVM_FIRST + 75;
        private const uint LVM_GETITEMPOSITION = LVM_FIRST + 16;
        private const uint LVM_SETITEMW = LVM_FIRST + 76;
        private const uint LVM_SETITEMPOSITION = LVM_FIRST + 15;
        [DllImport("user32.dll")]
        private static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
        [DllImport("user32.dll")]
        private static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, uint lParam);
        [DllImport("user32.dll")]
        private static extern IntPtr FindWindow(string lpszClass, string lpszWindow);
        [DllImport("user32.dll")]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint dwProcessId);
        private const uint PROCESS_VM_OPERATION = 0x0008;
        private const uint PROCESS_VM_READ = 0x0010;
        private const uint PROCESS_VM_WRITE = 0x0020;
        [DllImport("kernel32.dll")]
        private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
        private const uint MEM_COMMIT = 0x1000;
        private const uint MEM_RELEASE = 0x8000;
        private const uint MEM_RESERVE = 0x2000;
        private const uint PAGE_READWRITE = 4;
        [DllImport("kernel32.dll")]
        private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
        [DllImport("kernel32.dll")]
        private static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint dwFreeType);
        [DllImport("kernel32.dll")]
        private static extern bool CloseHandle(IntPtr handle);
        [DllImport("kernel32.dll")]
        private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, ref uint vNumberOfBytesRead);
        [DllImport("kernel32.dll")]
        private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, ref uint vNumberOfBytesRead);
        private struct LVITEM  //结构体
        {
            public int mask;
            public int iItem;
            public int iSubItem;
            public int state;
            public int stateMask;
            public IntPtr pszText; // string
            public int cchTextMax;
            public int iImage;
            public IntPtr lParam;
            public int iIndent;
            public int iGroupId;
            public int cColumns;
            public IntPtr puColumns;
        }
        private int LVIF_TEXT = 0x0001;
        #endregion

        private bool _is32bit;
        public DesktopIcon(bool is32bit)
        {
            _is32bit = is32bit;
        }

        //获取有多少个桌面图标
        private int ListView_GetItemCount(IntPtr AHandle)
        {
            return SendMessage(AHandle, LVM_GETITEMCOUNT, 0, 0);
        }

        //获取图标位置
        private bool ListView_GetItemPosition(IntPtr AHandle, int AIndex, IntPtr APoint)
        {
            return SendMessage(AHandle, LVM_GETITEMPOSITION, AIndex, APoint.ToInt32()) != 0;
        }

        //算图标的位置
        private uint MakelParam(double wLow, double wHigh)
        {
            return (uint)(wHigh * 0x10000 + wLow);
        }

        //获取文件或文件夹大小
        private void GetSize(string path, out bool isFile, out long size, out bool isSystemFile)
        {
            if (File.Exists(path))
            {
                FileInfo fileInfo = new FileInfo(path);
                isFile = true;
                size = fileInfo.Length;
                isSystemFile = false;
                return;
            }
            if (File.Exists(path + ".lnk"))
            {
                FileInfo fileInfo = new FileInfo(path + ".lnk");
                isFile = true;
                size = fileInfo.Length;
                isSystemFile = false;
                return;
            }
            if (Directory.Exists(path))
            {
                isFile = false;
                size = 100000000;//GetDirSize(path);
                isSystemFile = false;
                return;
            }
            {
                isFile = false;
                isSystemFile = true;
                size = 200000000000;
                return;
            }
        }

        //获取文件夹大小
        private long GetDirSize(string path)
        {
            DirectoryInfo dir = new DirectoryInfo(path);
            long count = 0;
            if (dir.Exists)
            {
                foreach (FileSystemInfo fi in dir.GetFileSystemInfos())
                {
                    if (fi.Attributes == FileAttributes.Directory)
                    {
                        count += GetDirSize(fi.FullName);
                    }
                    else
                    {
                        FileInfo finf = new FileInfo(fi.FullName);
                        count += finf.Length;
                    }
                }
            }
            return count;
        }

        //获取DesktopIcons列表
        private List<Icon> GetDesktopIcons()
        {
            //获取桌面路径
            string desktopPath = GetDesktopPath();
            List<Icon> IconList = new List<Icon>();
            //桌面上SysListView32的窗口句柄
            IntPtr vHandle;
            IntPtr vDesktopViewHandle = new IntPtr(0);
            //xp是Progman ; win7 网上说应该是 "WorkerW"  但是 spy++ 没找到 程序也不正常
            if (_is32bit)
            {
                vHandle = FindWindow("Progman", null);
                vHandle = FindWindowEx(vHandle, IntPtr.Zero, "SHELLDLL_DefView", null);
                vHandle = FindWindowEx(vHandle, IntPtr.Zero, "SysListView32", null);
            }
            else
            {
                vHandle = FindWindow("WorkerW", null);
                while ((vDesktopViewHandle != IntPtr.Zero) && vHandle == IntPtr.Zero)
                {
                    vDesktopViewHandle = FindWindowEx(vHandle, IntPtr.Zero, "SHELLDLL_DefView", null);
                    vHandle = FindWindowEx(IntPtr.Zero, vDesktopViewHandle, "WorkerW", null);
                }
                vHandle = FindWindowEx(vDesktopViewHandle, IntPtr.Zero, "SysListView32", "FolderView");
            }
            int vItemCount = ListView_GetItemCount(vHandle);//个数
            uint vProcessId; //进程 pid
            GetWindowThreadProcessId(vHandle, out vProcessId);
            //打开并插入进程
            IntPtr vProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, vProcessId);
            IntPtr vPointer = VirtualAllocEx(vProcess, IntPtr.Zero, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
            Point[] vPoint = new Point[1];
            try
            {
                for (int i = 0; i < vItemCount; i++)
                {
                    byte[] vBuffer = new byte[256];
                    LVITEM[] vItem = new LVITEM[1];
                    vItem[0].mask = LVIF_TEXT;
                    vItem[0].iItem = i;
                    vItem[0].iSubItem = 0;
                    vItem[0].cchTextMax = vBuffer.Length;
                    vItem[0].pszText = (IntPtr)((int)vPointer + Marshal.SizeOf(typeof(LVITEM)));
                    uint vNumberOfBytesRead = 0;
                    /// 分配内存空间
                    WriteProcessMemory(vProcess, vPointer, Marshal.UnsafeAddrOfPinnedArrayElement(vItem, 0), Marshal.SizeOf(typeof(LVITEM)), ref vNumberOfBytesRead);
                    //发送信息 获取响应
                    SendMessage(vHandle, LVM_GETITEMW, i, vPointer.ToInt32());
                    ReadProcessMemory(vProcess, (IntPtr)((int)vPointer + Marshal.SizeOf(typeof(LVITEM))), Marshal.UnsafeAddrOfPinnedArrayElement(vBuffer, 0), vBuffer.Length, ref vNumberOfBytesRead);
                    //获取图标的Title
                    string vText = Encoding.Unicode.GetString(vBuffer, 0, (int)vNumberOfBytesRead);
                    //对图标的Title进行处理
                    int index = vText.IndexOf('\0');
                    vText = vText.Substring(0, index);
                    //获取Icon的位置
                    ListView_GetItemPosition(vHandle, i, vPointer);
                    ReadProcessMemory(vProcess, vPointer, Marshal.UnsafeAddrOfPinnedArrayElement(vPoint, 0), Marshal.SizeOf(typeof(System.Drawing.Point)), ref vNumberOfBytesRead);
                    bool isFile;
                    long length;
                    bool isSystemFile;
                    GetSize(desktopPath + "\\" + vText, out isFile, out length, out isSystemFile);
                    //添加Icon到列表中
                    IconList.Add(new Icon()
                    {
                        Name = vText,
                        Point = vPoint[0],
                        hWnd = vHandle,
                        Index = i,
                        IsFile = isFile,
                        Size = length,
                        IsSystemFile = isSystemFile
                    });
                }
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
            finally
            {
                VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE);
                CloseHandle(vProcess);
                IconList = IconList.OrderBy(z => z.Size).ToList();
            }
            return IconList;
        }

        //获取系统桌面路径
        public string GetDesktopPath()
        {
            return Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
        }

        //获取平台的版本
        public string GetSysVer()
        {
            return Environment.OSVersion.Version.ToString();
        }

        /// <summary>
        /// 获取所有桌面项目的名称
        /// </summary>
        /// <returns></returns>
        public List<Icon> GetDesktopIconList()
        {
            return GetDesktopIcons();
        }

        /// <summary>
        /// 获取某个桌面项目的位置
        /// </summary>
        /// <param name="icoName"></param>
        /// <returns></returns>
        public Point GetDesktopIconPoint(string iconName)
        {
            List<Icon> iconList = GetDesktopIcons();
            Icon icon = iconList.Find(z => z.Name == iconName);
            if (icon != null)
            {
                return icon.Point;
            }
            else
            {
                throw new Exception("尚未找到相对应的桌面图标");
            }
        }

        /// <summary>
        /// 设置某个桌面项目的位置
        /// </summary>
        /// <param name="icoName"></param>
        /// <returns></returns>
        public void SetDesktopIconPoint(string iconName, Point point)
        {
            List<Icon> iconList = GetDesktopIcons();
            Icon icon = iconList.Find(z => z.Name == iconName);
            if (icon != null)
            {
                SendMessage(icon.hWnd, LVM_SETITEMPOSITION, icon.Index, MakelParam(point.X, point.Y));
            }
            else
            {
                throw new Exception("尚未找到相对应的桌面图标");
            }
        }
    }

    //桌面图标的Model
    class Icon
    {
        public string Name { get; set; }
        public Point Point { get; set; }
        public IntPtr hWnd { get; set; }
        public int Index { get; set; }
        public long Size { get; set; }
        public bool IsFile { get; set; }
        public bool IsSystemFile { get; set; }
    }
}
